import mongoose from 'mongoose';
import { UserRole, IUserRole, IUserRoleDocument, ApprovalStatus } from '../models/userRole';

/**
 * 用户角色关联数据访问对象
 * 提供用户角色关联相关的数据库操作方法
 */
export class UserRoleDAO {
  /**
   * 创建新的用户角色关联
   * @param userRoleData 用户角色关联数据
   * @returns 创建的用户角色关联文档
   */
  async create(userRoleData: Partial<IUserRole>): Promise<IUserRoleDocument> {
    try {
      const userRole = new UserRole(userRoleData);
      return await userRole.save();
    } catch (error: any) {
      if (error.code === 11000) {
        // 处理唯一性约束错误
        throw new Error('User role assignment already exists');
      }
      throw error;
    }
  }

  /**
   * 根据ID查找用户角色关联
   * @param id 用户角色关联ID
   * @returns 用户角色关联文档或null
   */
  async findById(id: mongoose.Types.ObjectId | string): Promise<IUserRoleDocument | null> {
    try {
      if (!id) {
        throw new Error('UserRole ID is required');
      }
      
      if (!mongoose.Types.ObjectId.isValid(id)) {
        throw new Error('Invalid userRole ID format');
      }
      
      return await UserRole.findById(id)
        .populate('userId')
        .populate('roleId')
        .populate('systemId')
        .populate('assignedBy')
        .populate('approvedBy');
    } catch (error) {
      throw error;
    }
  }

  /**
   * 根据用户ID查找用户角色关联
   * @param userId 用户ID
   * @param systemId 系统ID（可选）
   * @returns 用户角色关联文档数组
   */
  async findByUserId(
    userId: mongoose.Types.ObjectId | string,
    systemId?: mongoose.Types.ObjectId | string
  ): Promise<IUserRoleDocument[]> {
    try {
      if (!userId) {
        throw new Error('User ID is required');
      }
      
      if (!mongoose.Types.ObjectId.isValid(userId)) {
        throw new Error('Invalid user ID format');
      }
      
      const userObjectId = typeof userId === 'string' ? new mongoose.Types.ObjectId(userId) : userId;
      let systemObjectId: mongoose.Types.ObjectId | undefined;
      
      if (systemId) {
        if (!mongoose.Types.ObjectId.isValid(systemId)) {
          throw new Error('Invalid system ID format');
        }
        systemObjectId = typeof systemId === 'string' ? new mongoose.Types.ObjectId(systemId) : systemId;
      }
      
      return await UserRole.findByUserId(userObjectId, systemObjectId);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 根据角色ID查找用户角色关联
   * @param roleId 角色ID
   * @param systemId 系统ID（可选）
   * @returns 用户角色关联文档数组
   */
  async findByRoleId(
    roleId: mongoose.Types.ObjectId | string,
    systemId?: mongoose.Types.ObjectId | string
  ): Promise<IUserRoleDocument[]> {
    try {
      if (!roleId) {
        throw new Error('Role ID is required');
      }
      
      if (!mongoose.Types.ObjectId.isValid(roleId)) {
        throw new Error('Invalid role ID format');
      }
      
      const roleObjectId = typeof roleId === 'string' ? new mongoose.Types.ObjectId(roleId) : roleId;
      let systemObjectId: mongoose.Types.ObjectId | undefined;
      
      if (systemId) {
        if (!mongoose.Types.ObjectId.isValid(systemId)) {
          throw new Error('Invalid system ID format');
        }
        systemObjectId = typeof systemId === 'string' ? new mongoose.Types.ObjectId(systemId) : systemId;
      }
      
      return await UserRole.findByRoleId(roleObjectId, systemObjectId);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 根据系统ID查找用户角色关联
   * @param systemId 系统ID
   * @returns 用户角色关联文档数组
   */
  async findBySystemId(systemId: mongoose.Types.ObjectId | string): Promise<IUserRoleDocument[]> {
    try {
      if (!systemId) {
        throw new Error('System ID is required');
      }
      
      if (!mongoose.Types.ObjectId.isValid(systemId)) {
        throw new Error('Invalid system ID format');
      }
      
      const systemObjectId = typeof systemId === 'string' ? new mongoose.Types.ObjectId(systemId) : systemId;
      return await UserRole.findBySystemId(systemObjectId);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 检查用户是否拥有指定角色
   * @param userId 用户ID
   * @param roleId 角色ID
   * @param systemId 系统ID（可选）
   * @returns 是否拥有角色
   */
  async hasRole(
    userId: mongoose.Types.ObjectId | string,
    roleId: mongoose.Types.ObjectId | string,
    systemId?: mongoose.Types.ObjectId | string
  ): Promise<boolean> {
    try {
      if (!userId || !roleId) {
        throw new Error('User ID and Role ID are required');
      }
      
      if (!mongoose.Types.ObjectId.isValid(userId) || !mongoose.Types.ObjectId.isValid(roleId)) {
        throw new Error('Invalid user ID or role ID format');
      }
      
      const userObjectId = typeof userId === 'string' ? new mongoose.Types.ObjectId(userId) : userId;
      const roleObjectId = typeof roleId === 'string' ? new mongoose.Types.ObjectId(roleId) : roleId;
      let systemObjectId: mongoose.Types.ObjectId | undefined;
      
      if (systemId) {
        if (!mongoose.Types.ObjectId.isValid(systemId)) {
          throw new Error('Invalid system ID format');
        }
        systemObjectId = typeof systemId === 'string' ? new mongoose.Types.ObjectId(systemId) : systemId;
      }
      
      return await UserRole.hasRole(userObjectId, roleObjectId, systemObjectId);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 批量分配角色
   * @param assignments 角色分配数据数组
   * @returns 创建的用户角色关联文档数组
   */
  async batchAssign(assignments: Partial<IUserRole>[]): Promise<IUserRoleDocument[]> {
    try {
      if (!assignments || !Array.isArray(assignments) || assignments.length === 0) {
        throw new Error('Assignments array is required and cannot be empty');
      }
      
      // 验证每个分配数据的必要字段
      for (const assignment of assignments) {
        if (!assignment.userId || !assignment.roleId || !assignment.assignedBy) {
          throw new Error('userId, roleId, and assignedBy are required for each assignment');
        }
        
        if (!mongoose.Types.ObjectId.isValid(assignment.userId) || 
            !mongoose.Types.ObjectId.isValid(assignment.roleId) ||
            !mongoose.Types.ObjectId.isValid(assignment.assignedBy)) {
          throw new Error('Invalid ObjectId format in assignment data');
        }
      }
      
      return await UserRole.batchAssign(assignments);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 批量撤销角色
   * @param userId 用户ID
   * @param roleIds 角色ID数组
   * @param systemId 系统ID（可选）
   * @returns 撤销的角色数量
   */
  async batchRevoke(
    userId: mongoose.Types.ObjectId | string,
    roleIds: (mongoose.Types.ObjectId | string)[],
    systemId?: mongoose.Types.ObjectId | string
  ): Promise<number> {
    try {
      if (!userId || !roleIds || !Array.isArray(roleIds) || roleIds.length === 0) {
        throw new Error('User ID and role IDs array are required');
      }
      
      if (!mongoose.Types.ObjectId.isValid(userId)) {
        throw new Error('Invalid user ID format');
      }
      
      // 验证所有角色ID
      for (const roleId of roleIds) {
        if (!mongoose.Types.ObjectId.isValid(roleId)) {
          throw new Error('Invalid role ID format in roleIds array');
        }
      }
      
      const userObjectId = typeof userId === 'string' ? new mongoose.Types.ObjectId(userId) : userId;
      const roleObjectIds = roleIds.map(id => 
        typeof id === 'string' ? new mongoose.Types.ObjectId(id) : id
      );
      
      let systemObjectId: mongoose.Types.ObjectId | undefined;
      if (systemId) {
        if (!mongoose.Types.ObjectId.isValid(systemId)) {
          throw new Error('Invalid system ID format');
        }
        systemObjectId = typeof systemId === 'string' ? new mongoose.Types.ObjectId(systemId) : systemId;
      }
      
      return await UserRole.batchRevoke(userObjectId, roleObjectIds, systemObjectId);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 删除用户角色关联
   * @param id 用户角色关联ID
   * @returns 是否删除成功
   */
  async delete(id: mongoose.Types.ObjectId | string): Promise<boolean> {
    try {
      if (!id) {
        throw new Error('UserRole ID is required');
      }
      
      if (!mongoose.Types.ObjectId.isValid(id)) {
        throw new Error('Invalid userRole ID format');
      }
      
      // 先查找记录是否存在
      const userRole = await UserRole.findById(id);
      if (!userRole) {
        return false;
      }
      
      // 检查是否可以删除
      if (!userRole.canBeDeleted()) {
        throw new Error('UserRole cannot be deleted due to business constraints');
      }
      
      const result = await UserRole.findByIdAndDelete(id);
      return !!result;
    } catch (error) {
      throw error;
    }
  }

  /**
   * 获取用户在指定系统的所有角色
   * @param userId 用户ID
   * @param systemId 系统ID
   * @returns 用户角色关联文档数组
   */
  async getUserRolesInSystem(
    userId: mongoose.Types.ObjectId | string,
    systemId: mongoose.Types.ObjectId | string
  ): Promise<IUserRoleDocument[]> {
    try {
      if (!userId || !systemId) {
        throw new Error('User ID and System ID are required');
      }
      
      if (!mongoose.Types.ObjectId.isValid(userId) || !mongoose.Types.ObjectId.isValid(systemId)) {
        throw new Error('Invalid user ID or system ID format');
      }
      
      const userObjectId = typeof userId === 'string' ? new mongoose.Types.ObjectId(userId) : userId;
      const systemObjectId = typeof systemId === 'string' ? new mongoose.Types.ObjectId(systemId) : systemId;
      
      return await UserRole.getUserRolesInSystem(userObjectId, systemObjectId);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 获取待审批的角色分配
   * @param systemId 系统ID（可选）
   * @returns 待审批的用户角色关联文档数组
   */
  async getPendingApprovals(systemId?: mongoose.Types.ObjectId | string): Promise<IUserRoleDocument[]> {
    try {
      let systemObjectId: mongoose.Types.ObjectId | undefined;
      
      if (systemId) {
        if (!mongoose.Types.ObjectId.isValid(systemId)) {
          throw new Error('Invalid system ID format');
        }
        systemObjectId = typeof systemId === 'string' ? new mongoose.Types.ObjectId(systemId) : systemId;
      }
      
      return await UserRole.getPendingApprovals(systemObjectId);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 获取即将过期的角色分配
   * @param days 天数
   * @returns 即将过期的用户角色关联文档数组
   */
  async getExpiringRoles(days: number): Promise<IUserRoleDocument[]> {
    try {
      if (typeof days !== 'number' || days < 0) {
        throw new Error('Days must be a non-negative number');
      }
      
      return await UserRole.getExpiringRoles(days);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 清理过期的角色分配
   * @returns 清理的角色分配数量
   */
  async cleanupExpiredRoles(): Promise<number> {
    try {
      return await UserRole.cleanupExpiredRoles();
    } catch (error) {
      throw error;
    }
  }

  /**
   * 更新用户角色关联状态
   * @param id 用户角色关联ID
   * @param status 新状态
   * @returns 更新后的用户角色关联文档或null
   */
  async updateStatus(
    id: mongoose.Types.ObjectId | string,
    status: number
  ): Promise<IUserRoleDocument | null> {
    try {
      if (!id) {
        throw new Error('UserRole ID is required');
      }
      
      if (!mongoose.Types.ObjectId.isValid(id)) {
        throw new Error('Invalid userRole ID format');
      }
      
      if (typeof status !== 'number' || ![0, 1].includes(status)) {
        throw new Error('Status must be 0 or 1');
      }
      
      return await UserRole.findByIdAndUpdate(
        id,
        { status },
        { new: true, runValidators: true }
      ).populate('userId').populate('roleId').populate('systemId');
    } catch (error) {
      throw error;
    }
  }

  /**
   * 审批角色分配
   * @param id 用户角色关联ID
   * @param approvedBy 审批人ID
   * @param approved 是否批准
   * @returns 更新后的用户角色关联文档
   */
  async approve(
    id: mongoose.Types.ObjectId | string,
    approvedBy: mongoose.Types.ObjectId | string,
    approved: boolean
  ): Promise<IUserRoleDocument> {
    try {
      if (!id || !approvedBy) {
        throw new Error('UserRole ID and approvedBy are required');
      }
      
      if (!mongoose.Types.ObjectId.isValid(id) || !mongoose.Types.ObjectId.isValid(approvedBy)) {
        throw new Error('Invalid userRole ID or approvedBy format');
      }
      
      const userRole = await UserRole.findById(id);
      if (!userRole) {
        throw new Error('UserRole not found');
      }
      
      const approvedByObjectId = typeof approvedBy === 'string' ? new mongoose.Types.ObjectId(approvedBy) : approvedBy;
      return await userRole.approve(approvedByObjectId, approved);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 查找所有用户角色关联（支持分页和筛选）
   * @param criteria 查询条件
   * @param options 查询选项
   * @returns 分页查询结果
   */
  async findAll(
    criteria: {
      userId?: mongoose.Types.ObjectId | string;
      roleId?: mongoose.Types.ObjectId | string;
      systemId?: mongoose.Types.ObjectId | string;
      approvalStatus?: ApprovalStatus;
      status?: number;
    } = {},
    options: {
      page?: number;
      limit?: number;
      sort?: string;
      select?: string;
    } = {}
  ): Promise<{ userRoles: IUserRoleDocument[]; total: number; page: number; totalPages: number }> {
    try {
      const {
        page = 1,
        limit = 10,
        sort = '-assignedAt',
        select
      } = options;
      
      // 构建查询条件
      const query: any = {};
      
      if (criteria.userId) {
        if (!mongoose.Types.ObjectId.isValid(criteria.userId)) {
          throw new Error('Invalid user ID format');
        }
        query.userId = criteria.userId;
      }
      
      if (criteria.roleId) {
        if (!mongoose.Types.ObjectId.isValid(criteria.roleId)) {
          throw new Error('Invalid role ID format');
        }
        query.roleId = criteria.roleId;
      }
      
      if (criteria.systemId) {
        if (!mongoose.Types.ObjectId.isValid(criteria.systemId)) {
          throw new Error('Invalid system ID format');
        }
        query.systemId = criteria.systemId;
      }
      
      if (criteria.approvalStatus) {
        if (!Object.values(ApprovalStatus).includes(criteria.approvalStatus)) {
          throw new Error('Invalid approval status');
        }
        query.approvalStatus = criteria.approvalStatus;
      }
      
      if (criteria.status !== undefined) {
        if (![0, 1].includes(criteria.status)) {
          throw new Error('Status must be 0 or 1');
        }
        query.status = criteria.status;
      }
      
      // 计算跳过的文档数
      const skip = (page - 1) * limit;
      
      // 执行查询
      let queryBuilder = UserRole.find(query)
        .populate('userId')
        .populate('roleId')
        .populate('systemId')
        .populate('assignedBy')
        .populate('approvedBy')
        .sort(sort)
        .skip(skip)
        .limit(limit);
      
      if (select) {
        queryBuilder = queryBuilder.select(select);
      }
      
      const [userRoles, total] = await Promise.all([
        queryBuilder.exec(),
        UserRole.countDocuments(query)
      ]);
      
      const totalPages = Math.ceil(total / limit);
      
      return {
        userRoles,
        total,
        page,
        totalPages
      };
    } catch (error) {
      throw error;
    }
  }
}

export default UserRoleDAO;